#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
交互式可视化仪表板

提供实时优化监控和智能决策建议的Web界面：
1. 实时优化进度监控
2. 算法性能对比可视化
3. 决策建议展示
4. 交互式参数调整
"""

import streamlit as st
import plotly.graph_objects as go
import plotly.express as px
from plotly.subplots import make_subplots
import pandas as pd
import numpy as np
from typing import Dict, List, Any, Optional
import time
import threading
from datetime import datetime, timedelta
import json
from dataclasses import asdict

try:
    from .models import (
        OptimizationProblem, DecisionVariable, ObjectiveFunction,
        VariableType, OptimizationType, ConstraintType
    )
    from .advanced_algorithms import AdvancedAlgorithmEngine, AlgorithmResult
    from .intelligent_selector import IntelligentAlgorithmSelector
    from .hybrid_optimizer import HybridOptimizer
except ImportError:
    from models import (
        OptimizationProblem, DecisionVariable, ObjectiveFunction,
        VariableType, OptimizationType, ConstraintType
    )
    from advanced_algorithms import AdvancedAlgorithmEngine, AlgorithmResult
    from intelligent_selector import IntelligentAlgorithmSelector
    from hybrid_optimizer import HybridOptimizer


class OptimizationDashboard:
    """优化仪表板"""
    
    def __init__(self):
        self.algorithm_engine = AdvancedAlgorithmEngine()
        self.intelligent_selector = IntelligentAlgorithmSelector()
        self.hybrid_optimizer = HybridOptimizer()
        self.current_results = {}
        self.optimization_history = []
        self.real_time_data = {
            'timestamps': [],
            'fitness_values': {},
            'algorithm_status': {}
        }
        
        # 初始化Streamlit页面配置
        if 'initialized' not in st.session_state:
            st.set_page_config(
                page_title="MCP决策优化服务仪表板",
                page_icon="📊",
                layout="wide",
                initial_sidebar_state="expanded"
            )
            st.session_state.initialized = True
    
    def run(self):
        """运行仪表板"""
        st.title("🚀 MCP决策优化服务仪表板")
        st.markdown("---")
        
        # 侧边栏
        self._render_sidebar()
        
        # 主要内容区域
        tab1, tab2, tab3, tab4, tab5 = st.tabs([
            "📈 实时监控", "🔧 问题配置", "📊 性能分析", 
            "🎯 算法对比", "📋 历史记录"
        ])
        
        with tab1:
            self._render_real_time_monitoring()
        
        with tab2:
            self._render_problem_configuration()
        
        with tab3:
            self._render_performance_analysis()
        
        with tab4:
            self._render_algorithm_comparison()
        
        with tab5:
            self._render_history()
    
    def _render_sidebar(self):
        """渲染侧边栏"""
        st.sidebar.header("🎛️ 控制面板")
        
        # 系统状态
        st.sidebar.subheader("系统状态")
        
        # 模拟系统指标
        cpu_usage = np.random.uniform(20, 80)
        memory_usage = np.random.uniform(30, 70)
        active_optimizations = len(self.current_results)
        
        col1, col2 = st.sidebar.columns(2)
        with col1:
            st.metric("CPU使用率", f"{cpu_usage:.1f}%")
            st.metric("活跃优化", active_optimizations)
        
        with col2:
            st.metric("内存使用率", f"{memory_usage:.1f}%")
            st.metric("总任务数", len(self.optimization_history))
        
        st.sidebar.markdown("---")
        
        # 快速操作
        st.sidebar.subheader("快速操作")
        
        if st.sidebar.button("🔄 刷新数据"):
            st.rerun()
        
        if st.sidebar.button("🧹 清除历史"):
            self.optimization_history.clear()
            self.real_time_data = {
                'timestamps': [],
                'fitness_values': {},
                'algorithm_status': {}
            }
            st.success("历史数据已清除")
        
        # 算法统计
        st.sidebar.subheader("算法统计")
        algorithm_stats = self.intelligent_selector.get_algorithm_statistics()
        
        if algorithm_stats:
            for alg_name, stats in algorithm_stats.items():
                with st.sidebar.expander(f"📊 {alg_name}"):
                    st.write(f"执行次数: {stats['count']}")
                    st.write(f"平均时间: {stats['avg_time']:.2f}s")
                    st.write(f"平均适应度: {stats['avg_fitness']:.3f}")
                    st.write(f"成功率: {stats['success_rate']:.1%}")
    
    def _render_real_time_monitoring(self):
        """渲染实时监控"""
        st.header("📈 实时优化监控")
        
        # 创建实时图表容器
        chart_container = st.empty()
        metrics_container = st.empty()
        
        # 如果有正在运行的优化
        if self.current_results:
            # 显示当前优化状态
            with metrics_container.container():
                cols = st.columns(len(self.current_results))
                
                for i, (alg_name, result) in enumerate(self.current_results.items()):
                    with cols[i]:
                        st.metric(
                            label=f"🔄 {alg_name}",
                            value=f"{result.best_fitness:.4f}",
                            delta=f"{result.execution_time:.2f}s"
                        )
            
            # 绘制收敛曲线
            with chart_container.container():
                self._plot_convergence_curves()
        
        else:
            st.info("🔍 当前没有正在运行的优化任务")
            
            # 显示示例数据
            if st.button("🎲 生成示例数据"):
                self._generate_sample_data()
                st.rerun()
    
    def _render_problem_configuration(self):
        """渲染问题配置界面"""
        st.header("🔧 优化问题配置")
        
        # 问题基本信息
        col1, col2 = st.columns(2)
        
        with col1:
            st.subheader("基本设置")
            problem_name = st.text_input("问题名称", "新优化问题")
            problem_type = st.selectbox("问题类型", ["单目标优化", "多目标优化"])
            
        with col2:
            st.subheader("算法设置")
            auto_select = st.checkbox("智能算法选择", True)
            if not auto_select:
                selected_algorithm = st.selectbox(
                    "选择算法",
                    self.algorithm_engine.get_available_algorithms()
                )
        
        # 决策变量配置
        st.subheader("📊 决策变量")
        
        if 'variables' not in st.session_state:
            st.session_state.variables = []
        
        # 添加变量
        with st.expander("➕ 添加决策变量"):
            col1, col2, col3, col4 = st.columns(4)
            
            with col1:
                var_name = st.text_input("变量名称")
            with col2:
                var_type = st.selectbox("变量类型", ["连续", "整数", "二进制"])
            with col3:
                lower_bound = st.number_input("下界", value=0.0)
            with col4:
                upper_bound = st.number_input("上界", value=10.0)
            
            if st.button("添加变量") and var_name:
                type_mapping = {"连续": VariableType.CONTINUOUS, 
                              "整数": VariableType.INTEGER, 
                              "二进制": VariableType.BINARY}
                
                variable = DecisionVariable(
                    name=var_name,
                    variable_type=type_mapping[var_type],
                    lower_bound=lower_bound,
                    upper_bound=upper_bound
                )
                
                st.session_state.variables.append(variable)
                st.success(f"已添加变量: {var_name}")
        
        # 显示当前变量
        if st.session_state.variables:
            st.subheader("当前变量")
            
            var_data = []
            for var in st.session_state.variables:
                var_data.append({
                    "名称": var.name,
                    "类型": var.variable_type.value,
                    "下界": var.lower_bound,
                    "上界": var.upper_bound
                })
            
            df = pd.DataFrame(var_data)
            st.dataframe(df, use_container_width=True)
            
            if st.button("🗑️ 清除所有变量"):
                st.session_state.variables = []
                st.rerun()
        
        # 目标函数配置
        st.subheader("🎯 目标函数")
        
        objective_expression = st.text_area(
            "目标函数表达式 (Python代码)",
            "# 示例: 最大化 x1^2 + x2^2\nreturn solution['x1']**2 + solution['x2']**2",
            height=100
        )
        
        optimization_type = st.selectbox("优化类型", ["最大化", "最小化"])
        
        # 约束条件
        st.subheader("⚖️ 约束条件")
        
        constraint_expression = st.text_area(
            "约束条件 (Python代码，返回True表示满足约束)",
            "# 示例: x1 + x2 <= 10\nreturn solution['x1'] + solution['x2'] <= 10",
            height=80
        )
        
        # 开始优化
        st.markdown("---")
        
        col1, col2, col3 = st.columns(3)
        
        with col1:
            if st.button("🚀 开始优化", type="primary"):
                if st.session_state.variables and objective_expression:
                    self._start_optimization(
                        st.session_state.variables,
                        objective_expression,
                        optimization_type,
                        constraint_expression,
                        auto_select,
                        selected_algorithm if not auto_select else None
                    )
                else:
                    st.error("请至少添加一个决策变量和目标函数")
        
        with col2:
            if st.button("⏹️ 停止优化"):
                self.current_results.clear()
                st.success("优化已停止")
        
        with col3:
            if st.button("💾 保存配置"):
                st.success("配置已保存")
    
    def _render_performance_analysis(self):
        """渲染性能分析"""
        st.header("📊 性能分析")
        
        if not self.optimization_history:
            st.info("📈 暂无历史数据用于分析")
            return
        
        # 性能指标概览
        st.subheader("📈 性能指标概览")
        
        # 计算统计数据
        algorithms = list(set(result['algorithm'] for result in self.optimization_history))
        
        metrics_data = []
        for algorithm in algorithms:
            alg_results = [r for r in self.optimization_history if r['algorithm'] == algorithm]
            
            if alg_results:
                avg_time = np.mean([r['execution_time'] for r in alg_results])
                avg_fitness = np.mean([r['best_fitness'] for r in alg_results])
                success_rate = len([r for r in alg_results if r['best_fitness'] > 0]) / len(alg_results)
                
                metrics_data.append({
                    '算法': algorithm,
                    '平均执行时间(s)': f"{avg_time:.2f}",
                    '平均适应度': f"{avg_fitness:.4f}",
                    '成功率': f"{success_rate:.1%}",
                    '执行次数': len(alg_results)
                })
        
        if metrics_data:
            df_metrics = pd.DataFrame(metrics_data)
            st.dataframe(df_metrics, use_container_width=True)
        
        # 性能对比图表
        col1, col2 = st.columns(2)
        
        with col1:
            st.subheader("⏱️ 执行时间对比")
            self._plot_execution_time_comparison()
        
        with col2:
            st.subheader("🎯 适应度对比")
            self._plot_fitness_comparison()
        
        # 趋势分析
        st.subheader("📈 性能趋势")
        self._plot_performance_trends()
    
    def _render_algorithm_comparison(self):
        """渲染算法对比"""
        st.header("🎯 算法对比分析")
        
        if len(self.current_results) < 2:
            st.info("🔄 需要至少运行两个算法才能进行对比")
            
            # 提供快速对比功能
            if st.button("🚀 运行算法对比"):
                self._run_algorithm_comparison()
            return
        
        # 实时对比
        st.subheader("📊 实时算法对比")
        
        # 创建对比表格
        comparison_data = []
        for alg_name, result in self.current_results.items():
            comparison_data.append({
                '算法': alg_name,
                '当前最优值': f"{result.best_fitness:.6f}",
                '执行时间': f"{result.execution_time:.2f}s",
                '迭代次数': result.iterations,
                '状态': '运行中' if result.execution_time < 60 else '已完成'
            })
        
        df_comparison = pd.DataFrame(comparison_data)
        st.dataframe(df_comparison, use_container_width=True)
        
        # 收敛曲线对比
        st.subheader("📈 收敛曲线对比")
        self._plot_convergence_comparison()
        
        # 算法特性雷达图
        st.subheader("🕸️ 算法特性分析")
        self._plot_algorithm_radar_chart()
    
    def _render_history(self):
        """渲染历史记录"""
        st.header("📋 优化历史记录")
        
        if not self.optimization_history:
            st.info("📝 暂无历史记录")
            return
        
        # 历史记录表格
        st.subheader("📊 历史记录表")
        
        # 转换历史数据为DataFrame
        history_data = []
        for i, record in enumerate(self.optimization_history):
            history_data.append({
                'ID': i + 1,
                '时间': record.get('timestamp', 'N/A'),
                '算法': record['algorithm'],
                '最优值': f"{record['best_fitness']:.6f}",
                '执行时间': f"{record['execution_time']:.2f}s",
                '变量数': record.get('num_variables', 'N/A'),
                '状态': '成功' if record['best_fitness'] > 0 else '失败'
            })
        
        df_history = pd.DataFrame(history_data)
        
        # 添加筛选功能
        col1, col2, col3 = st.columns(3)
        
        with col1:
            algorithm_filter = st.selectbox(
                "筛选算法",
                ['全部'] + list(set(record['algorithm'] for record in self.optimization_history))
            )
        
        with col2:
            date_filter = st.date_input("筛选日期")
        
        with col3:
            status_filter = st.selectbox("筛选状态", ['全部', '成功', '失败'])
        
        # 应用筛选
        filtered_df = df_history.copy()
        
        if algorithm_filter != '全部':
            filtered_df = filtered_df[filtered_df['算法'] == algorithm_filter]
        
        if status_filter != '全部':
            filtered_df = filtered_df[filtered_df['状态'] == status_filter]
        
        st.dataframe(filtered_df, use_container_width=True)
        
        # 导出功能
        col1, col2 = st.columns(2)
        
        with col1:
            if st.button("📥 导出CSV"):
                csv = filtered_df.to_csv(index=False)
                st.download_button(
                    label="下载CSV文件",
                    data=csv,
                    file_name=f"optimization_history_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv",
                    mime="text/csv"
                )
        
        with col2:
            if st.button("📊 生成报告"):
                self._generate_optimization_report(filtered_df)
    
    def _plot_convergence_curves(self):
        """绘制收敛曲线"""
        fig = go.Figure()
        
        for alg_name, result in self.current_results.items():
            if result.convergence_history:
                fig.add_trace(go.Scatter(
                    x=list(range(len(result.convergence_history))),
                    y=result.convergence_history,
                    mode='lines+markers',
                    name=alg_name,
                    line=dict(width=2)
                ))
        
        fig.update_layout(
            title="实时收敛曲线",
            xaxis_title="迭代次数",
            yaxis_title="适应度值",
            hovermode='x unified',
            height=400
        )
        
        st.plotly_chart(fig, use_container_width=True)
    
    def _plot_convergence_comparison(self):
        """绘制收敛曲线对比"""
        fig = go.Figure()
        
        colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7']
        
        for i, (alg_name, result) in enumerate(self.current_results.items()):
            if result.convergence_history:
                fig.add_trace(go.Scatter(
                    x=list(range(len(result.convergence_history))),
                    y=result.convergence_history,
                    mode='lines+markers',
                    name=alg_name,
                    line=dict(width=3, color=colors[i % len(colors)]),
                    marker=dict(size=6)
                ))
        
        fig.update_layout(
            title="算法收敛性能对比",
            xaxis_title="迭代次数",
            yaxis_title="适应度值",
            hovermode='x unified',
            height=500,
            showlegend=True
        )
        
        st.plotly_chart(fig, use_container_width=True)
    
    def _plot_algorithm_radar_chart(self):
        """绘制算法特性雷达图"""
        if len(self.current_results) < 2:
            return
        
        # 计算各算法的特性指标
        algorithms = list(self.current_results.keys())
        categories = ['收敛速度', '解质量', '稳定性', '计算效率', '全局搜索能力']
        
        fig = go.Figure()
        
        for alg_name, result in self.current_results.items():
            # 模拟特性评分（实际应用中应基于真实性能数据）
            convergence_speed = min(1.0, 1.0 / (result.execution_time + 0.1))
            solution_quality = min(1.0, max(0.0, result.best_fitness))
            stability = 0.8  # 模拟值
            efficiency = min(1.0, 1.0 / (result.execution_time + 0.1))
            global_search = 0.7  # 模拟值
            
            values = [convergence_speed, solution_quality, stability, efficiency, global_search]
            
            fig.add_trace(go.Scatterpolar(
                r=values,
                theta=categories,
                fill='toself',
                name=alg_name,
                line=dict(width=2)
            ))
        
        fig.update_layout(
            polar=dict(
                radialaxis=dict(
                    visible=True,
                    range=[0, 1]
                )
            ),
            title="算法特性雷达图",
            height=500
        )
        
        st.plotly_chart(fig, use_container_width=True)
    
    def _plot_execution_time_comparison(self):
        """绘制执行时间对比"""
        if not self.optimization_history:
            return
        
        algorithms = list(set(record['algorithm'] for record in self.optimization_history))
        
        data = []
        for algorithm in algorithms:
            times = [r['execution_time'] for r in self.optimization_history if r['algorithm'] == algorithm]
            data.extend([(algorithm, time) for time in times])
        
        if data:
            df = pd.DataFrame(data, columns=['算法', '执行时间'])
            fig = px.box(df, x='算法', y='执行时间', title="执行时间分布")
            fig.update_layout(height=400)
            st.plotly_chart(fig, use_container_width=True)
    
    def _plot_fitness_comparison(self):
        """绘制适应度对比"""
        if not self.optimization_history:
            return
        
        algorithms = list(set(record['algorithm'] for record in self.optimization_history))
        
        data = []
        for algorithm in algorithms:
            fitness_values = [r['best_fitness'] for r in self.optimization_history if r['algorithm'] == algorithm]
            data.extend([(algorithm, fitness) for fitness in fitness_values])
        
        if data:
            df = pd.DataFrame(data, columns=['算法', '适应度'])
            fig = px.violin(df, x='算法', y='适应度', title="适应度分布")
            fig.update_layout(height=400)
            st.plotly_chart(fig, use_container_width=True)
    
    def _plot_performance_trends(self):
        """绘制性能趋势"""
        if len(self.optimization_history) < 5:
            return
        
        # 按时间排序
        sorted_history = sorted(self.optimization_history, 
                              key=lambda x: x.get('timestamp', datetime.now()))
        
        df_data = []
        for i, record in enumerate(sorted_history):
            df_data.append({
                '序号': i + 1,
                '算法': record['algorithm'],
                '适应度': record['best_fitness'],
                '执行时间': record['execution_time']
            })
        
        df = pd.DataFrame(df_data)
        
        fig = make_subplots(
            rows=2, cols=1,
            subplot_titles=('适应度趋势', '执行时间趋势'),
            vertical_spacing=0.1
        )
        
        # 适应度趋势
        for algorithm in df['算法'].unique():
            alg_data = df[df['算法'] == algorithm]
            fig.add_trace(
                go.Scatter(
                    x=alg_data['序号'],
                    y=alg_data['适应度'],
                    mode='lines+markers',
                    name=f'{algorithm} (适应度)',
                    showlegend=True
                ),
                row=1, col=1
            )
        
        # 执行时间趋势
        for algorithm in df['算法'].unique():
            alg_data = df[df['算法'] == algorithm]
            fig.add_trace(
                go.Scatter(
                    x=alg_data['序号'],
                    y=alg_data['执行时间'],
                    mode='lines+markers',
                    name=f'{algorithm} (时间)',
                    showlegend=False
                ),
                row=2, col=1
            )
        
        fig.update_layout(height=600, title="性能趋势分析")
        st.plotly_chart(fig, use_container_width=True)
    
    def _start_optimization(self, variables, objective_expr, opt_type, 
                          constraint_expr, auto_select, selected_algorithm):
        """开始优化"""
        try:
            # 创建优化问题
            problem = self._create_optimization_problem(
                variables, objective_expr, opt_type, constraint_expr
            )
            
            # 创建目标函数
            def objective_function(solution):
                try:
                    # 安全执行用户代码
                    local_vars = {'solution': solution, 'np': np, 'math': __import__('math')}
                    return eval(objective_expr.split('return')[1].strip(), {"__builtins__": {}}, local_vars)
                except:
                    return float('-inf')
            
            # 选择算法
            if auto_select:
                algorithm_name, params = self.intelligent_selector.select_best_algorithm(problem)
            else:
                algorithm_name = selected_algorithm
                params = {}
            
            # 运行优化
            with st.spinner(f"正在运行 {algorithm_name} 算法..."):
                result = self.algorithm_engine.optimize_with_algorithm(
                    algorithm_name, problem, objective_function, **params
                )
                
                # 保存结果
                self.current_results[algorithm_name] = result
                
                # 记录历史
                history_record = {
                    'timestamp': datetime.now(),
                    'algorithm': algorithm_name,
                    'best_fitness': result.best_fitness,
                    'execution_time': result.execution_time,
                    'num_variables': len(variables)
                }
                self.optimization_history.append(history_record)
                
                # 记录性能数据
                self.intelligent_selector.record_performance(
                    algorithm_name, problem, result, params
                )
            
            st.success(f"✅ {algorithm_name} 优化完成！")
            st.json({
                "最优解": result.best_solution,
                "最优值": result.best_fitness,
                "执行时间": f"{result.execution_time:.2f}秒"
            })
            
        except Exception as e:
            st.error(f"❌ 优化过程中出现错误: {str(e)}")
    
    def _create_optimization_problem(self, variables, objective_expr, 
                                   opt_type, constraint_expr):
        """创建优化问题"""
        # 创建目标函数
        opt_type_enum = OptimizationType.MAXIMIZE if opt_type == "最大化" else OptimizationType.MINIMIZE
        
        objective = ObjectiveFunction(
            name="user_objective",
            expression=objective_expr,
            optimization_type=opt_type_enum
        )
        
        # 创建约束（如果有）
        constraints = []
        if constraint_expr.strip():
            from models import Constraint
            constraint = Constraint(
                name="user_constraint",
                expression=constraint_expr,
                constraint_type=ConstraintType.INEQUALITY
            )
            constraints.append(constraint)
        
        return OptimizationProblem(
            name="user_problem",
            variables=variables,
            objectives=[objective],
            constraints=constraints
        )
    
    def _generate_sample_data(self):
        """生成示例数据"""
        algorithms = ['differential_evolution', 'ant_colony', 'artificial_bee_colony']
        
        for alg in algorithms:
            # 模拟结果
            convergence_history = []
            current_fitness = np.random.uniform(0.1, 0.3)
            
            for i in range(50):
                current_fitness += np.random.uniform(-0.01, 0.02)
                current_fitness = max(0, current_fitness)
                convergence_history.append(current_fitness)
            
            from advanced_algorithms import AlgorithmResult
            result = AlgorithmResult(
                best_solution={'x1': np.random.uniform(0, 10), 'x2': np.random.uniform(0, 10)},
                best_fitness=current_fitness,
                convergence_history=convergence_history,
                execution_time=np.random.uniform(1, 10),
                iterations=50,
                algorithm_name=alg,
                metadata={}
            )
            
            self.current_results[alg] = result
    
    def _run_algorithm_comparison(self):
        """运行算法对比"""
        st.info("🚀 正在运行算法对比...")
        self._generate_sample_data()
        st.success("✅ 算法对比完成！")
        st.rerun()
    
    def _generate_optimization_report(self, df):
        """生成优化报告"""
        st.subheader("📊 优化报告")
        
        # 统计信息
        total_runs = len(df)
        successful_runs = len(df[df['状态'] == '成功'])
        success_rate = successful_runs / total_runs if total_runs > 0 else 0
        
        col1, col2, col3 = st.columns(3)
        
        with col1:
            st.metric("总运行次数", total_runs)
        with col2:
            st.metric("成功次数", successful_runs)
        with col3:
            st.metric("成功率", f"{success_rate:.1%}")
        
        # 算法性能排名
        if not df.empty:
            algorithm_performance = df.groupby('算法').agg({
                '最优值': 'mean',
                '执行时间': 'mean',
                '状态': lambda x: (x == '成功').mean()
            }).round(4)
            
            algorithm_performance.columns = ['平均最优值', '平均执行时间', '成功率']
            algorithm_performance = algorithm_performance.sort_values('平均最优值', ascending=False)
            
            st.subheader("🏆 算法性能排名")
            st.dataframe(algorithm_performance, use_container_width=True)


def main():
    """主函数"""
    dashboard = OptimizationDashboard()
    dashboard.run()


if __name__ == "__main__":
    main()